#pragma once
#include <netinet/in.h>
#include <string>
#include "XnccAddress.h"
namespace xncc {
namespace foundation {
    class IpV6Address final : public XnccAddress
    {
      public:
        using s_ptr = std::shared_ptr<IpV6Address>;
        explicit IpV6Address(const std::string& addr, int protocol = IPPROTO_TCP);
        explicit IpV6Address(const struct sockaddr_in6& addr, int protocol = IPPROTO_TCP);
        explicit IpV6Address(int protocol = IPPROTO_TCP);
        ~IpV6Address() override;

        IpV6Address(const IpV6Address&)             = delete;
        IpV6Address(const IpV6Address&&)            = delete;
        IpV6Address& operator=(const IpV6Address&)  = delete;
        IpV6Address& operator=(const IpV6Address&&) = delete;

        [[nodiscard]] auto Type() const -> shared::XNCC_ADDR_TYPE override
        {
            return protocol_ == IPPROTO_TCP ? shared::XNCC_ADDR_TYPE::IPV6_TCP : shared::XNCC_ADDR_TYPE::IPV6_UDP;
        }

        [[nodiscard]] auto family() const -> sa_family_t override { return addr_.sin6_family; }

        [[nodiscard]] auto toStr() const -> std::string override { return toIpPort(); }

        [[nodiscard]] auto getSockAddr() const -> const struct sockaddr* override
        {
            return reinterpret_cast<const struct sockaddr*>(&addr_);
        }

        [[nodiscard]] socklen_t getSockLen() const override { return static_cast<socklen_t>(sizeof(addr_)); }

        void setSockAddr(const struct sockaddr_in6& addr) { addr_ = addr; }

        [[nodiscard]] std::string toIp() const;
        [[nodiscard]] uint16_t    toPort() const;
        [[nodiscard]] std::string toIpPort() const;

      private:
        struct sockaddr_in6 addr_ = {};
        const int           protocol_;
    };
}  // namespace foundation
}  // namespace xncc